﻿#pragma once

struct _stProvinceInfo;
struct FontCharSet;

enum _eDirULDR
{
	DirNone = -1,
	DirMin = 0,
	Up = DirMin,
	Left,
	Down,
	Right,
	DirMax,
};

class CStrategyRenderData
{
public:
	CStrategyRenderData() = default;
	~CStrategyRenderData() = default;

	HRESULT CreateRenderTexture(IDirect3DDevice9* pd3dDevice);
	void	OnFrameMove(const D3DVIEWPORT9* pViewPort);
	void    OnDestroyDevice();

public:
	LPDIRECT3DTEXTURE9				m_pTexTerrainDiffuse;	// 地形集
	LPDIRECT3DTEXTURE9				m_pTexHeightNormal;		// 地图法线
	LPDIRECT3DTEXTURE9				m_pTexTerrainColorTint;	// 地图颜色色调
	LPDIRECT3DTEXTURE9				m_pTexTerrainNormal;	// 地形法线
	LPDIRECT3DTEXTURE9				m_pTexTerrainIDMap;		// 地形图

	LPDIRECT3DTEXTURE9				m_pTexRiverSurfaceDiffuse;	// 河流表面纹理
	LPDIRECT3DTEXTURE9				m_pTexRiverSurfaceNormal;	// 河流表面法线
	LPDIRECT3DTEXTURE9				m_pTexRiverBottomDiffuse;	// 河流底部纹理
	LPDIRECT3DTEXTURE9				m_pTexRiverBottomNormal;	// 河流底部法线

	LPDIRECT3DTEXTURE9				m_pTexBorderDiffuse;	// 边界纹理

private:
	std::set<int> m_set_RenderSquare;
public:
	bool GetRenderSquareSet(std::set<int>* set_RenderSquareOut) const;
	bool UpdateRenderSquare(std::set<int>* set_RenderSquareOut);
private:
	int m_nRenderAreaWidth = 0;
	int m_nRenderAreaHeight = 0;
public:
	bool GetRenderAreaWH(int* nWidth, int* nHeight);	// 得到渲染的地图的分格的行列

private:
	friend class CProgramDataMgr;
	bool TransformTerrainMap(const BYTE* pTerrainID);	// 转化 地形图
	std::unique_ptr<BYTE[]> m_pTerrainID = nullptr;		// 在TransformTerrainMap中赋值

	D3DVIEWPORT9 m_ViewPort;
};

class CStrategyRenderFunc
{
public:
	static void GetTerrainXYByScreenPos(float fScreenX, float fScreenY, CPoint& ptOut);		// 未拉伸
	static float GetHeightByFloatXY(float x, float y);
	static int GetTerrainIndexBFloatXY(float x, float y);
	static int GetRenderSquareIndex(float x, float y);

	// 取得名字的fnt字体的总宽和总高
	static void GetNameSumWidthNHeightInFNT(float& SumWidthOut, float& SumHeightOut, const std::wstring& name, const FontCharSet* pFntFace, BYTE SpaceWidth = 0);		// 输出总字符宽度 总字符高度 输入名字 fnt接口 空格宽度
	// 通过2点 得到名字显示的中轴线和方向向量、法向量
	static void GetNameMiddleLine(D3DXVECTOR2& pointStartOut, D3DXVECTOR2& DirectionVectorOut, D3DXVECTOR2& NormalVectorOut, bool& bLineVerticalOut, const D3DXVECTOR2& pointA, const D3DXVECTOR2& pointB, DWORD SumWidthIn, DWORD SumHeightIn);	// 输出起点 方向单位向量 向右或向下的单位法向量 是否是纵向 输入线上的2个点 总字符宽度 总字符高度

public:
	template <typename T>
	static bool IsPointLegal(const T& pt, int nWidth=c_nTerrainWidth, int nHeight=c_nTerrainHeight)		// 检测点合法性
	{
		if (pt.x < 0 || pt.x >= nWidth ||
			pt.y < 0 || pt.y >= nHeight)
		{
			return false;
		}
		return true;
	}
	template <typename T>
	static bool DirTrans2XY(_eDirULDR eDir, const T& ptIn, T& ptOut, int nWidth=c_nTerrainWidth, int nHeight=c_nTerrainHeight)
	{
		T ptTemp = ptIn;
		switch (eDir)
		{
		case Up:
			ptTemp.y += 1;
			break;
		case Left:
			ptTemp.x -= 1;
			break;
		case Down:
			ptTemp.y -= 1;
			break;
		case Right:
			ptTemp.x += 1;
			break;
		default:
			return false;
			break;
		}
		if (IsPointLegal(ptTemp, nWidth, nHeight))
		{
			ptOut = ptTemp;
			return true;
		}
		else
		{
			return false;
		}
	}
	template <typename T>
	static bool XYTrans2Dir(const T& pt1, const T& pt2, _eDirULDR& eDir)		// 从pt1到pt2的方向
	{
		float offX = pt2.x - pt1.x;
		float offY = pt2.y - pt1.y;
		if (0 == offX && offY > 0)
		{
			eDir = Up;
			return true;
		}
		else if (offX < 0 && 0 == offY)
		{
			eDir = Left;
			return true;
		}
		else if (0 == offX && offY < 0)
		{
			eDir = Down;
			return true;
		}
		else if (offX > 0 && 0 == offY)
		{
			eDir = Right;
			return true;
		}
		else
		{
			return false;
		}
	}
	template <typename T>
	static bool RebuildBodyList(std::deque<T>& tBody, DWORD dwFuzzy, bool bBuildTransMap, std::unordered_map<DWORD, D3DXVECTOR2>* mapPointTrans, float fXYoffset, bool bDeletePointInStraightLine)
	{
		if (bBuildTransMap)
		{
			CHECK_RE_FALSE(mapPointTrans);
		}

		int nSize = (int)tBody.size();
		if (nSize < 2)
		{
			CString strErr(L"dequeBody is too short!");
			CommonFunc::ErrorMessageBox(strErr);
			return false;
		}

		tBody[0].vec2 += D3DXVECTOR2(fXYoffset, fXYoffset);
		// 先遍历一遍 找出所有起点+拐点+尾点
		struct _stKneeInfo
		{
			DWORD index;		// 在原_dequeBody中的索引
			_eDirULDR eDirNext;	// 目前不需要记方向，记方向是为了生成曲线
		};
		std::deque<_stKneeInfo> dequeKneeInfo;
		_eDirULDR eDirFront = DirNone;
		D3DXVECTOR2 fpFront = tBody[0].vec2;
		for (int i = 1; i < nSize; ++i)
		{
			tBody[i].vec2 += D3DXVECTOR2(fXYoffset, fXYoffset);

			_eDirULDR eDir;
			if (!CStrategyRenderFunc::XYTrans2Dir(fpFront, tBody[i].vec2, eDir))
			{
				CString strErr;
				strErr.Format(L"Can't transform (%d, %d), (%d, %d) to direction", fpFront.x, fpFront.y, tBody[i].vec2.x, tBody[i].vec2.y);
				CommonFunc::ErrorMessageBox(strErr);
				return false;
			}
			if (eDirFront != eDir)		// 首 + 拐
			{
				eDirFront = eDir;
				_stKneeInfo stKneeInfo;
				stKneeInfo.index = i - 1;
				stKneeInfo.eDirNext = eDir;
				dequeKneeInfo.push_back(stKneeInfo);
			}
			if (nSize - 1 == i)		// 尾
			{
				_stKneeInfo stKneeInfo;
				stKneeInfo.index = i;
				stKneeInfo.eDirNext = DirNone;
				dequeKneeInfo.push_back(stKneeInfo);
			}
			fpFront = tBody[i].vec2;
		}

		if (dequeKneeInfo.size() > 2)
		{
			for (auto iter = dequeKneeInfo.begin() + 2; iter != dequeKneeInfo.end(); ++iter)
			{
				DWORD indexFirst = (iter - 2)->index;
				DWORD indexSecond = (iter - 1)->index;
				DWORD indexThird = iter->index;
				// 如果3个拐点都相邻 就删除中间的拐点
				if (1 == indexSecond - indexFirst && 1 == indexThird - indexSecond)
				{
					iter = dequeKneeInfo.erase(iter - 1);
				}
			}
		}
		
		// 光滑拐点附近的点 dwFuzzy决定 [center - dwFuzzy] 到 [center + dwFuzzy]上的点一一映射到 tBody[center - dwFuzzy]和tBody[center + dwFuzzy]形成的直线上 通过线性插值
		// 曲线以后再说 zwb_promising
		// 根据bDeletePointInStraightLine决定是否删除中间节点
		{
			std::deque<T> tempBody;
			if (dequeKneeInfo.size() <= 2)		// 直线
			{
				if (bDeletePointInStraightLine)
				{
					tempBody.push_back(tBody.front());
					tempBody.push_back(tBody.back());
					tBody = std::move(tempBody);		// tempBody失效
				}
				// 不删除 就不用做操作了
			}
			else
			{
				for (int i = 2; i < (int)dequeKneeInfo.size(); i += 1)
				{
					DWORD indexFirst = dequeKneeInfo[i - 2].index;
					DWORD indexSecond = dequeKneeInfo[i - 1].index;
					DWORD indexThird = dequeKneeInfo[i].index;
					DWORD indexTransformHead = 0;
					DWORD indexTransformTail = 0;
					bool bCreateHeadTemp = false;
					D3DXVECTOR2 vec2HeadTemp;		// 临时线段起点
					bool bCreateTailTemp = false;
					D3DXVECTOR2 vec2TailTemp;		// 临时线段钟点

					// 根据dwFuzzy决定变换到的参与变换的起始终止点
					if (indexSecond - indexFirst >= 2 * dwFuzzy)
					{
						indexTransformHead = indexSecond - dwFuzzy;
					}
					else if (1 == indexSecond - indexFirst)
					{
						if (2 == i)
						{
							indexTransformHead = indexFirst;
						}
						else
						{
							// 创建中间点
							bCreateHeadTemp = true;
							vec2HeadTemp = (tBody[indexFirst].vec2 + tBody[indexSecond].vec2) / 2.f;
							indexTransformHead = indexSecond - 1;
						}
					}
					else
					{
						if (2 == i)		// 第一次进来 可以变换首拐点 其余只能变换首拐点和中拐点的1/2点到中拐点 上的点
						{
							if (indexSecond - indexFirst >= dwFuzzy)
							{
								indexTransformHead = indexSecond - dwFuzzy;
							}
							else
							{
								indexTransformHead = indexFirst;
							}
						}
						else
						{
							indexTransformHead = indexSecond - (indexSecond - indexFirst) / 2;
						}
					}

					if (indexThird - indexSecond >= 2 * dwFuzzy)
					{
						indexTransformTail = indexThird - dwFuzzy;
					}
					else if (1 == indexThird - indexSecond)
					{
						if (dequeKneeInfo.size() - 1 == i)
						{
							indexTransformTail = indexThird;
						}
						else
						{
							// 创建中间点
							bCreateTailTemp = true;
							vec2TailTemp = (tBody[indexSecond].vec2 + tBody[indexThird].vec2) / 2.f;
							indexTransformTail = indexSecond + 1;
						}
					}
					else
					{
						if (dequeKneeInfo.size() - 1 == i)
						{
							if (indexThird - indexSecond >= dwFuzzy)
							{
								indexTransformTail = indexSecond + dwFuzzy;
							}
							else
							{
								indexTransformTail = indexThird;
							}
						}
						else
						{
							indexTransformTail = indexSecond + (indexThird - indexSecond) / 2;
						}
					}

					DWORD OperateHead = 0;			// 向tempBody push的索引
					DWORD OperateTail = 0;
					// 对于正好在中间的点 和 创建的中间点 原则是push_back First和second之间的
					if (2 == i)
					{
						OperateHead = indexFirst;
					}
					else
					{
						OperateHead = indexSecond - (indexSecond - indexFirst) / 2;
					}
					if (dequeKneeInfo.size() - 1 == i)
					{
						OperateTail = indexThird;
					}
					else
					{
						OperateTail = indexSecond + (indexThird - indexSecond) / 2;
						if (0 == (indexThird - indexSecond) % 2)
						{
							OperateTail -= 1;
						}
					}
							
					if (bDeletePointInStraightLine)		// 如果要删除无用节点 就不需要变换了
					{
						if (2 == i)
						{
							tempBody.push_back(tBody.front());
						}
						if (bCreateHeadTemp)
						{
							T st(tBody[indexSecond]);
							st.vec2 = vec2HeadTemp;
							tempBody.push_back(st);
						}
						else if (indexTransformHead != indexFirst)
						{
							tempBody.push_back(tBody[indexTransformHead]);
						}
						if (bCreateTailTemp)
						{
							if (indexSecond + 1 <= OperateTail)
							{
								T st(tBody[indexSecond]);
								st.vec2 = vec2TailTemp;
								tempBody.push_back(st);
							}
						}
						else if (indexTransformTail != indexThird && indexTransformTail <= OperateTail)
						{
							tempBody.push_back(tBody[indexTransformTail]);
						}
						if (dequeKneeInfo.size() - 1 == i)
						{							
							tempBody.push_back(tBody.back());
						}
					}
					else
					{
						// 变换点
						if (!bCreateHeadTemp)
						{
							vec2HeadTemp = tBody[indexTransformHead].vec2;
						}
						if (!bCreateTailTemp)
						{
							vec2TailTemp = tBody[indexTransformTail].vec2;
						}
						D3DXVECTOR2 v2OffHT = vec2TailTemp - vec2HeadTemp;
						if (0 == v2OffHT.x || 0 == v2OffHT.y)
						{
							CString strErr;
							strErr.Format(L"(%d, %d), (%d, %d) is illegal!", vec2HeadTemp.x, vec2HeadTemp.y, vec2TailTemp.x, vec2TailTemp.y);
							CommonFunc::ErrorMessageBox(strErr);
							return false;
						}
						float fHTDistance2 = pow(v2OffHT.x, 2) + pow(v2OffHT.y, 2);
						for (DWORD j = indexTransformHead + 1; j < indexTransformTail; ++j)
						{
							// HJ到HT的投影距离 = HJ*HT/|HT| lerp值就是HJ*HT/|HT|2
							D3DXVECTOR2 v2OffHJ = tBody[j].vec2 - vec2HeadTemp;
							float fLerp = CMathFunc::Lerp(0.f, 1.f, D3DXVec2Dot(&v2OffHJ, &v2OffHT) / fHTDistance2);
							tBody[j].vec2 = vec2HeadTemp + fLerp * v2OffHT;
						}

						// 变换完之后 操作tempBody
						for (DWORD j = OperateHead; j <= OperateTail; ++j)
						{
							if (indexSecond == j && bCreateHeadTemp)
							{
								T st(tBody[indexSecond]);
								st.vec2 = vec2HeadTemp;
								tempBody.push_back(st);
							}
							tempBody.push_back(tBody[j]);
							if (indexSecond == j && bCreateTailTemp && dequeKneeInfo.size() - 1 == i)
							{
								T st(tBody[indexSecond]);
								st.vec2 = vec2TailTemp;
								tempBody.push_back(st);
							}
						}
					}
				}
				tBody = std::move(tempBody);		// tempBody失效
			}
		}
		
		if (bBuildTransMap && !bDeletePointInStraightLine)
		{
			DWORD indexBegin = CMathFunc::XYTran2Index(tBody.front().vec2.x, tBody.front().vec2.y, c_nTerrainWidth, c_nTerrainHeight);
			auto resultBegin = mapPointTrans->find(indexBegin);
			if (resultBegin != mapPointTrans->end())
			{
				tBody.front().vec2 = resultBegin->second;
			}

			DWORD indexEnd = CMathFunc::XYTran2Index(tBody.back().vec2.x, tBody.back().vec2.y, c_nTerrainWidth, c_nTerrainHeight);
			auto resultEnd = mapPointTrans->find(indexEnd);
			if (resultEnd != mapPointTrans->end())
			{
				tBody.back().vec2 = resultEnd->second;
			}
		}
		return true;
	}
};